home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-05-04 | 5.5 KB | 137 lines | [TEXT/GEOL] |
- Item 7715524 30-April-90 21:24PDT
-
- From: M.DANIEL Daniel Scientific, M Daniel,PRT
-
- To: CPLUS.APPLE$ C++ Interest List--Apple Employees
- CPLUS.DEV$ C++ Interest List--Developers
-
- Sub: RE> copy vs op= & constr err
-
- I have encountered both of these questions/problems. My solution involves
- creating a more explicit philosophy of "object" Then the answers come easy.
-
- My explicit philosophy is:
-
- Objects are created from nothing.
- Objects are destroyed to nothing.
- In between creation and destruction, the object is either:
- 1) in a definite state, or
- 2) transforming from one definite state into another definite state.
-
-
-
- Applied to C++:
-
- A constructor transforms nothing into an object. The memory allocation merely
- creates an empty "hole in space" where the object will exist on return from the
- constructor. Before the constructor call, the values in this memory are
- meaningless.
-
- Member functions transform the object from one state to another. In between
- member function calls, the object is in a definite well-defined state.
-
- A destructor transforms an object into nothing. An empty "hole in space." On
- return from it, the values of this memory are meaningless.
-
-
-
- Copy constructors vs assignment operators.
-
- A constructor has a right and an obligation to ignore the pre-existing values
- of the object. The pre-existing values are part of nothing. This is the
- nature of a constructor.
-
- An assignment operator has a right and an obligation to consider the
- pre-existing values of the object. The pre-existing values are part of an
- object. This is the nature of an assignment operator.
-
- So initialization and assignment are fundamentally different operations.
-
- Practically, consider an object that contains a handle as a data member.
- If the constructor assumes its non-zero (junk) value is really a handle...
- (There is even a small probability, that it will actually be a valid handle).
- Or if an assignment operator assumes its valid value is really junk...
-
-
- Constructor HELL
-
- When a constructor returns, its object must be in some definite state.
-
- Then when a member function is called, it determines the state of the object,
- and uses it to decide what new state to transform the object into (as well as
- performing whatever other side effects are desired).
-
- Practically, many object have only two states: OK and error. And the state
- information can be implicit. For example, a zero handle could mean error.
-
-
- The error handling/recovery thread
-
- One idea I'm experimenting with is using the public member function
- "operator int();" to report the state of the object. The basic idea is that to
- determine the state of an object, convert it to an integer. Then to check the
- state, write:
- if ( obj ) ...
-
- I can also write more complex expressions:
- if ( obj1 || ( obj2 && !obj3) ) ...
-
- But, things could get a little sticky if an object had a lot of operators
- defined for it. And even then, use an explicit int conversion:
- cout << (int)obj << obj;
-
- Using "operator int();" is, by definition, the only way to determine the state
- of an object. Specifically, no other member function, public or private,
- returns state information. This helps keep the error handling/recovery code
- thread from entangling the other code threads (ie. algorithm, interface,
- context-senstive help). The threads will cross at a minimum of simple,
- obvious, well-behaved places. If "operator int();" is inline, the generated
- code may even be better.
-
- Note: Philosophically speaking, the "operator int();" member function
- transforms the object from state A into state A. (ie it transforms the object,
- but the state does not change)
-
- I define two more member functions in the error handling/recovery thread.
-
- The first is the famous error() function. What I have it do is examine the
- object, determine the error, set the object to indicate the error state, and
- place the object in a stable state. This is the only function that transform
- the object into the error state. I attempt to have it determine error by
- examine the current objects (transient) state, and refrain from passing
- parameters to it, because they clutter up the source files.
-
- For example, an object may have several handles. If some are allocated when
- memory runs out, obj::error() would discover some zero handles, and release the
- rest of the memory, and set the state to reflect an error.
-
- The last error thread function is obj::recover(). It is the one and only
- member function that can change an object from an error state to a non-error
- state (ie. recover from an error). Don't forget to have it also handle objects
- that are not in an error state.
-
- I also use the ideas Michael Vilot mentioned (ie. if the state is error, I do
- nothing). Then the only place I check for object errors is at the beginning of
- certain member functions, and at strategic other locations. Then, during an
- error condition, the rest of the code just calls and returns until it reaches
- one of these strategic locations. If an error occurs during the execution of a
- member function, the obj::error() member function is called and the function
- returns.
-
- (Looks a lot like poor man's exception handling, uh?)
-
-
-
- Conclusion:
-
- I have essentially applied Directed Acyclic Graph theory to object programming.
- DAGs are not particularily new to computer science, but I've yet to see object
- programming described this way. Looks to me like an oppurtunity to create some
- new object-oriented CASE tools.
-
-
- Michael J. Daniel
- Daniel Scientific
- AppleLink:M.Daniel
-
-